package org.zjt.platform.springbootreactivedemo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.Charset;
import java.util.Date;
import java.util.Map;

/**
 * Description:
 *
 * @author juntao.zhang
 * Date: 2018-06-12 下午8:31
 * @see
 */
@Slf4j
public class CustomErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {

    public CustomErrorWebExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    }


    // Define constructor here

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(this.acceptsTextHtml(), this::renderErrorView).andRoute(RequestPredicates.all(), this::renderErrorResponse);
    }

    @Override
    protected Mono<ServerResponse> renderDefaultErrorView(ServerResponse.BodyBuilder responseBody, Map<String, Object> error) {
        StringBuilder builder = new StringBuilder();
        Object message = error.get("message");
        Date timestamp = (Date)error.get("timestamp");
        HttpStatus errorStatus = this.getHttpStatus(error);
        builder.append("<html><body><h1>自定义错误页面</h1><h2>👌</h2>").append(message).append(timestamp).append("<h3> http status:").append(errorStatus);
        builder.append("</h3></body></html>");
        Mono<ServerResponse> serverResponseMono = responseBody.syncBody(builder.toString());
        return serverResponseMono;
    }

    @Override
    protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
        boolean includeStackTrace = this.isIncludeStackTrace(request, MediaType.TEXT_HTML);
        Map<String, Object> error = this.getErrorAttributes(request, includeStackTrace);
        HttpStatus errorStatus = this.getHttpStatus(error);
        ServerResponse.BodyBuilder response = ServerResponse.status(errorStatus).header("Content-Type","text/html;charset=UTF-8");
        Mono<ServerResponse> monoMono = this.renderDefaultErrorView(response, error).doOnNext((resp) -> this.logError(request, errorStatus));
        return monoMono;
    }

    @Override
    protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
        boolean includeStackTrace = this.isIncludeStackTrace(request, MediaType.ALL);
        Map<String, Object> error = this.getErrorAttributes(request, includeStackTrace);
        HttpStatus errorStatus = this.getHttpStatus(error);
        return ServerResponse.status(this.getHttpStatus(error)).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(error))
                .doOnNext((resp) -> this.logError(request, errorStatus));
    }

}
